# -*- makefile -*-

# Targets in this Makefile:
# - all: Create C++ sources from Preprocess input
#
# This Makefile is invoked in a sub-Make from the top-level Makefile
# (via Makerules.global) when globalconfig.out, Modules and
# .Modules.deps are up-to-date.

all: do-all

BUILD_SOURCES=true

include $(srcdir)/Makeconf	# also reads srcdir/Makeconf.local
                                # and        objdir/Makeconf.local
include globalconfig.tags
include $(MODULES_FILE)
include .Modules.deps

include $(srcdir)/Makerules.global # also reads objdir/Makerules.local

# Read subsystem Makefile fragments.  We do not explicity use any
# targets of these fragments in this Makefile, but this include allows
# subsystem Makefile fragments to implicitly create more Makefile
# fragments.
include $(MAKERULES_SUBSYS)

ALL_STAMPS = $(foreach m, $(GENERATED_MODULES), auto/stamp-$(m).ready)

.PHONY: do-all
do-all: $(ALL_STAMPS)

#
# Auto-created source files
#
auto_clean_files = $(strip $(filter-out 				      \
	  $(addprefix auto/,				      		      \
	    $(addsuffix .cc,						      \
	      $(foreach mod, $(GENERATED_MODULES), $(call eval_impl,$(mod)))) \
	    $(foreach mod, $(GENERATED_MODULES), 			      \
			   $(mod).h $(mod)_i.h stamp-$(mod).ready)),	      \
	  $(wildcard auto/*)))

.Clean-auto: $(MODULES_FILES) .Modules.deps globalconfig.out
	$(if $(auto_clean_files),$(RM) $(auto_clean_files))
	touch $@

define find_ld_emulation
	emulations=$$(LC_ALL=C $(LD) --help |                             \
	              grep -i "supported emulations:" |                   \
	              sed -e 's/.*supported emulations: //') ;            \
	unset found_it;                                                   \
	for e in $$emulations; do                                         \
	  for c in $(2); do                                               \
	    if [ "$$e" = "$$c" ]; then                                    \
	      echo "LD_EMULATION_FLAG = -m $$e" >> $(1);                  \
	      found_it=1;                                                 \
	      break;                                                      \
	    fi;                                                           \
	  done;                                                           \
	  if [ "$$found_it" = "1" ]; then                                 \
	    break;                                                        \
	  fi;                                                             \
	done;                                                             \
	if [ "$$found_it" != "1" ]; then                                  \
	  echo "No known ld emulation found (available: $$emulations)";   \
	  exit 1;                                                         \
	fi
endef

# Force that rule to ensure that compiler changes caused by make command line
# or system-wide compiler updates are noticed.  
# Do not use .PHONY, because preprocess would then be triggered everytime.
.Compiler-config: force-the-rule
	@echo -n "Checking compiler config... "
	@echo "CC = $(CC)" > $@.new
	@echo "CXX = $(CXX)" >> $@.new
	@echo "CPPFLAGS = $(CPPFLAGS)" >> $@.new
	@echo "CFLAGS = $(CFLAGS)" >> $@.new
	@echo "CXXFLAGS = $(CXXFLAGS)" >> $@.new
	@echo "OPT_CFLAGS = $(OPT_CFLAGS)" >> $@.new
	@echo "OPT_CXXFLAGS = $(OPT_CXXFLAGS)" >> $@.new
	@echo "ASFLAGS = $(ASFLAGS)" >> $@.new
	@echo "CONFIG_XARCH = $(CONFIG_XARCH)" >> $@.new
# If the compiler configuration has changed, remove all dependency
# files -- they have just become useless.
# Since all object files are recompiled anyway when the compiler configuration
# has changed, also remove all generated source files, to avoid the situation
# that all generated source files are older than their ready stamp, resulting in
# a startup delay on each make run, due to their recipes being executed unnecessarily.
	@$(MOVE_IF_CHANGE) $@.new $@				\
	  && { $(RM) .*.d */.*.d  auto/*.cc auto/*.h auto/*.S; echo "CHANGED.  Recompiling."; }	\
	  || echo "unchanged."

# For the LLVM linker, -m cannot be detected as "ld.lld --help" does not list
# the supported emulations. But apparently it's also not necessary to pass this
# parameter.
ifeq ($(LD_TYPE),clang)
.Host-config:
else
.Host-config: force-the-rule
	@$(call find_ld_emulation,$@.new,$(LD_EMULATION_CHOICE))
	@$(MOVE_IF_CHANGE) $@.new $@ || true
endif

force-the-rule: ;

$(ALL_STAMPS): $(MODULES_FILES) .Modules.deps globalconfig.out \
	       .Clean-auto .Compiler-config .Host-config

# Basename of implementation files = Basename of first .cpp file
impl_name = $(basename $(firstword $(subst -, ,\
              $(firstword $(filter %.cpp, $(notdir $(1)))))))

preprocess_cmd = $(PREPROCESS) $(PREPROCESS_FLAGS) \
                   $(if $(filter $(call impl_name,$(1)),$(ALWAYS_INLINE)),-i,) \
                   -p auto/new_ -e "$(PREPROCESS_PARTS)" -s -h $(2) \
                   -c $(call impl_name,$(1)) $(filter %.cpp, $(1))

$(ALL_STAMPS): auto/stamp-%.ready: $(PREPROCESS) | auto
	$(PREP_MESSAGE)
	$(VERBOSE_PREP)touch $@
	$(VERBOSE_PREP)$(call preprocess_cmd,$^,$*)
	@for i in $*.h $(call impl_name,$^)_i.h \
	    $(patsubst %.cpp, %.cc, $(filter %.cpp, $(notdir $^))); \
	  do \
	    $(MOVE_IF_CHANGE) auto/new_$$i auto/$$i || true; \
	  done
	$(OK_MESSAGE)  

auto:
	@mkdir -p auto

.PRECIOUS: auto/stamp-%.ready
.PRECIOUS: %.cc %.h %_i.h

